package com.tianji.remark.service.impl;

import com.tianji.api.dto.remark.LikedTimesDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.remark.constants.RedisConstants;
import com.tianji.remark.domain.dto.LikeRecordFormDTO;
import com.tianji.remark.domain.po.LikedRecord;
import com.tianji.remark.mapper.LikedRecordMapper;
import com.tianji.remark.service.ILikedRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.StringRedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * <p>
 * 点赞记录表 服务实现类
 * </p>
 *
 * @author 林云
 * @since 2023-08-16
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LikedRecordServiceImpl extends ServiceImpl<LikedRecordMapper, LikedRecord> implements ILikedRecordService {

    private final RabbitMqHelper rabbitMqHelper;
    private final StringRedisTemplate redisTemplate;

    /**
     * 点赞或取消赞
     */
    @Override
    public void addLikeRecord(LikeRecordFormDTO dto) {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.判断点赞/取消点赞
        Boolean flag = true;
        flag = dto.getLiked() ? liked(dto, userId) : unLiked(dto, userId);
        if (!flag) {
            return;
        }
        //3.统计数量
        Long totalSum = redisTemplate.opsForSet().size(RedisConstants.LIKE_BIZ_KEY_PREFIX + dto.getBizType());
        if (totalSum == null) {
            return;
        }
        String totalSizeKey = RedisConstants.LIKE_COUNT_KEY_PREFIX + dto.getBizType();
        redisTemplate.opsForZSet().add(totalSizeKey, dto.getBizId().toString(), totalSum);
    }

    /**
     * 使用redis管道技术 批量查询点赞状态
     */
    @Override
    public Set<Long> queryLikedStatusBatch(List<Long> bizIds) {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.redis中查询记录
        List<Object> objects = redisTemplate.executePipelined((RedisCallback<?>) connection -> {
            for (Long bizId : bizIds) {
                String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + bizId;
                StringRedisConnection src = (StringRedisConnection) connection;
                src.sIsMember(key, userId.toString());
            }
            return null;
        });
        return IntStream.range(0, objects.size())
                .filter(i -> (boolean) objects.get(i))
                .mapToObj(bizIds::get)
                .collect(Collectors.toSet());
    }

    /**
     * 批量发送消息 List<LikedTimesDTO>
     */
    @Override
    public void readLikedTimesAndSendMessage(String bizType, Integer maxBizSize) {
        //1.拼接key likes:times:type:QA
        String key = RedisConstants.LIKE_COUNT_KEY_PREFIX + bizType;
        //2.从redis中获取数据
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().popMin(key, maxBizSize);
        if (CollUtils.isEmpty(typedTuples)) {
            return;
        }
        //3.封装为List<LikedTimesDTO>
        List<LikedTimesDTO> list = new ArrayList<>();
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
            String bizId = typedTuple.getValue();
            Double likedTimes = typedTuple.getScore();
            if (StringUtils.isBlank(bizId) || likedTimes == null) {
                continue;
            }
            //3.1封装为LikedTimesDTO
            LikedTimesDTO dto = LikedTimesDTO.builder()
                    .bizId(Long.valueOf(bizId))
                    .likedTimes(likedTimes.intValue())
                    .build();
            list.add(dto);
        }
        log.info("批量发送消息：{}", list);
        //4.获取routingKey
        String routingKey = StringUtils.format(
                MqConstants.Key.LIKED_TIMES_KEY_TEMPLATE,
                bizType);
        //5.批量发送消息  List<LikedTimesDTO>
        rabbitMqHelper.send(MqConstants.Exchange.LIKE_RECORD_EXCHANGE, routingKey, list);
    }

    /**
     * 取消点赞 从redis中移除某个值
     */
    private Boolean unLiked(LikeRecordFormDTO dto, Long userId) {
        //1.拼接key
        String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + dto.getBizId();
        //2.从redis中移除
        Long result = redisTemplate.opsForSet().remove(key, userId.toString());
        return result != null && result > 0;
    }

    /**
     * 点赞 以set形式添加到redis中 QA:123
     */
    private Boolean liked(LikeRecordFormDTO dto, Long userId) {
        //1.拼接key
        String key = RedisConstants.LIKE_BIZ_KEY_PREFIX + dto.getBizId();
        //2.添加到redis中
        Long result = redisTemplate.opsForSet().add(key, userId.toString());
        return result != null && result > 0;
    }

    /**
     * 批量查询点赞状态 从bizIds中筛选出点赞的
     */
    /*@Override
    public Set<Long> queryLikedStatusBatch(List<Long> bizIds) {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.查询点赞记录表 in bizIds
        List<LikedRecord> likedRecords = this.lambdaQuery()
                .in(LikedRecord::getBizId, bizIds)
                .eq(LikedRecord::getUserId, userId)
                .list();
        //3.收集bizId
        Set<Long> bizIdSet = likedRecords.stream().map(LikedRecord::getBizId).collect(Collectors.toSet());
        return bizIdSet;
    }*/

    /**
     * 点赞或取消赞
     */
    /*@Override
    public void addLikeRecord(LikeRecordFormDTO dto) {
        //1.获取用户id
        Long userId = UserContext.getUser();
        //2.判断是否是点赞
        boolean flag = true;
        //3.点赞和取消赞逻辑
        flag = dto.getLiked() ? liked(dto, userId) : unliked(dto, userId);
        if (!flag) {
            return;
        }
        //4.根据业务id 统计点赞数量
        Integer count = this.lambdaQuery().eq(LikedRecord::getBizId, dto.getBizId()).count();
        //5.发送MQ
        String routingKey = StringUtils.format(MqConstants.Key.LIKED_TIMES_KEY_TEMPLATE, dto.getBizType());
        LikedTimesDTO msg = LikedTimesDTO.builder().bizId(dto.getBizId()).likedTimes(count).build();
        log.info("【点赞服务】发送消息: {}", msg);
        rabbitMqHelper.send(MqConstants.Exchange.LIKE_RECORD_EXCHANGE,
                routingKey,
                msg);
    }*/

    /**
     * 点赞
     */
    /*private boolean liked(LikeRecordFormDTO dto, Long userId) {
        //1.查询点赞记录
        LikedRecord record = this.lambdaQuery()
                .eq(LikedRecord::getUserId, userId)
                .eq(LikedRecord::getBizId, dto.getBizId())
                .one();
        //2.点赞记录存在，不能重复点赞
        if (record != null) {
            return false;
        }
        //3.保存点赞记录
        LikedRecord likedRecord = new LikedRecord();
        likedRecord.setUserId(userId);
        likedRecord.setBizId(dto.getBizId());
        likedRecord.setBizType(dto.getBizType());
        return this.save(likedRecord);
    }*/

    /**
     * 取消赞
     */
    /*private boolean unliked(LikeRecordFormDTO dto, Long userId) {
        //1.查询点赞记录
        LikedRecord record = this.lambdaQuery()
                .eq(LikedRecord::getUserId, userId)
                .eq(LikedRecord::getBizId, dto.getBizId())
                .one();
        //2.点赞记录不存在则不能取消赞
        if (record == null) {
            return false;
        }
        //3.删除点赞记录
        return this.removeById(record.getId());
    }*/

}
